import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.File;

/**
 * parseConfigFile()
 * 1. polls the {PWD}/conf directory for new devices.
 * 2. outputs a "status message" reporting new device.
 * 3. initializes new device, parsing OPT values into a hash map.
 * 
 */


public class DeviceHandler extends Thread {
	public static Properties props;
	private String configFileDir, configFileName;
	private GmailUtils gmail = null;
	
	/**
	 * Constructor:
	 * @param homeDir, deviceName
	 */
	public DeviceHandler(String configFileDir, String configFileName){
		this.configFileDir = configFileDir;
		this.configFileName = configFileName;
		
		// Start the thread
		this.start();
	}

	@Override
	public void run() {

		// For every new device, perform parse config files to decide on arguments.
		props = FileUtils.fileToProps(this.configFileDir + "/" + this.configFileName);
		

		for (int i = 0; i<props.OPT_DEVICE_NAMES.size(); i++) {
			System.out.println("Eligible device name =" + props.OPT_DEVICE_NAMES.get(i));
		}
		
//		try {
//			this.join();
//		} catch (InterruptedException e) {
//			e.printStackTrace();
//		}
		
		// For every new device, begin to poll emails.
		while (true){
			try {
				// Polls the user's email account.
	            this.pollEmail();
	            
	            // Polls the output file (for sending ACKS to the user)
	            this.pollDeviceOutput();
	            
	            sleep(3000);
	        } catch(Exception e) {
	            e.printStackTrace();
	            System.exit(-1);
	        }
		}
	}
	
	private synchronized void pollEmail() throws Exception {
		 if (gmail == null) {
			 gmail = new GmailUtils();
			 //gmail.setUserPass("cheesecake88888@gmail.com", "cheesecakerevolution");
	         gmail.setUserPass(props.OPT_USER_COMMAND_EMAIL, props.OPT_USER_COMMAND_PWD);
	         System.out.println(props.OPT_USER_COMMAND_EMAIL + props.OPT_USER_COMMAND_PWD);
		 }
         gmail.connect();
         gmail.openFolder("INBOX");
		 
         int totalMessages = gmail.getMessageCount();
         int newMessages = gmail.getNewMessageCount();
         
         System.out.println(this.configFileName + " => Total messages = " + totalMessages);
         System.out.println(this.configFileName + " => New messages = " + newMessages);
         System.out.println("-------------------------------");

         if (newMessages > 0) {
        	 processUnreadMessages();
         }
         
         gmail.disconnect();
         
         //gmail.printAllMessageEnvelopes();
//         gmail.printAllMessages();
	}
	
	// Iterates through all unread messages and checks if the first token in
	// each unread message (i.e. the device identifier) corresponds with this
	// registered device. If so, this function sends the command text to the
	// device driver.
	private void processUnreadMessages() throws Exception{
		int totalMessages = gmail.getMessageCount();
        int newMessages = gmail.getNewMessageCount();
        
        for (int i = 0; i < newMessages; ++i) {
        	int messageIndex = totalMessages + i;
        	String sender = gmail.getMessageSender(messageIndex);
        	
        	if (!verifyMessageSender(sender)) continue;
        	
        	String message = gmail.extractFirstLine(messageIndex);
        	message.trim();
        	String tokens[] = message.split("[ \t]+");
        	for (int j = 0; j < props.OPT_DEVICE_NAMES.size(); ++j) {
            	if (tokens[0].equalsIgnoreCase(props.OPT_DEVICE_NAMES.elementAt(j))) {
            		sendCommandToDevice(tokens);
            	}		
        	}    	
        }
	}
	
	private boolean verifyMessageSender(String messageSender) {
		return messageSender.compareToIgnoreCase(props.OPT_USER_COMMAND_EMAIL) == 0;
		//return true;
	}
	
	/**
	 * 
	 * @param tokens
	 */
	private void sendCommandToDevice(String[] tokens) {
		//System.out.println(this.);
   		int numCommands = props.OPT_LIB_IN.size();
		String command;
		for (int i = 0; i < numCommands; ++i) {
			//
			String curLibIn = props.OPT_LIB_IN.elementAt(i);
			int commandIndex = curLibIn.indexOf(',');
			String curCommand = curLibIn.substring(0, commandIndex);
			curCommand.trim();
			String curArgs = curLibIn.substring(commandIndex + 2);
			curArgs.trim();
			String[] commandTokens = curCommand.split(" ");
			 
			// If the commands have different lengths then we shouldn't even consider it.
			if (commandTokens.length != tokens.length - 1) continue;
			
			boolean commandMatches = true;
			
			for (int j = 0; j < commandTokens.length; ++j) {
				if (!commandTokens[j].equalsIgnoreCase(tokens[j + 1])) {
					commandMatches = false;
					break;
				}
			}
			 
			if (commandMatches) {
				command = props.OPT_EXEPATH + " " + curArgs;
				if (props.OPT_EXE_REQUIRED) {
					try {
						//GmailUtils.pr(message);
						GmailUtils.pr("Executing: " + props.OPT_EXEPATH);
		    			Runtime rt = Runtime.getRuntime();
		    			rt.exec(command, null);
					} catch (Exception e) {
						GmailUtils.pr("Could not execute command!");
					}
				}
			}
		}
	}
	
	/**
	 * Checks if the specified output file exists. If it does, then
	 * the device driver has returned something that we need to send
	 * back to the user.
	 * @throws Exception
	 */
	private synchronized void pollDeviceOutput() throws Exception {
		//TODO: need lock
		File f = new File(props.OPT_OUTPUTPATH);
		
		// Checks if the specified output file exists. If it does, then
		// the device driver has returned something that we need to send
		// back to the user.
		if (f.exists()) {
			FileReader reader = new FileReader(props.OPT_OUTPUTPATH);
		    BufferedReader br = new BufferedReader(reader);
		    
		    // Reads the first line of the output text file and then sends
		    // a text file to the user.
		    String s = br.readLine();
		    if (s != null) {
				sendAcknowledgement(s);
		    }
		    
		    // To indicate that we've handled the output, we delete the
		    // output file. This makes sure we don't end up sending duplicate
		    // messages back to the user constantly.
		    br.close();
		    reader.close();
			f.delete();
		}
	}
	
	/**
	 * 
	 * @param message
	 */
	private void sendAcknowledgement(String message) {
		String recipientEmail = props.OPT_USER_MOBILE_EMAIL;
		String host = "smtp.gmail.com";
	    String from = Constants.username;
	    String pass = Constants.password;
	    
		SMSSender sms = new SMSSender(host, from, pass);
		sms.sendTextMessage(recipientEmail, message);
		
	}
	


}
